//-----------------------------------------------
//    module name: data_slot
//    author: Liang
//  
//    version: 1st version (2021-10-01)
//    description: 该模块用于CPU与MEMOEY以及MESH网络之间的数据传输，
//                  MESH网络上传输的数据采用数据包的格式
//
//
//-----------------------------------------------
`timescale 1ns / 1ps

module data_slot(

    input  wire        clk,
    input  wire        rstn,

    //CPU
    input  wire [ 3:0] data_bus_we,       
    input  wire [31:0] data_bus_addr_i,   
    input  wire [31:0] data_bus_data_i,   
    output wire [31:0] data_bus_data_o,   

    input  wire        data_req_valid_i,  
    output wire        data_rsp_valid_o,  

    //MEMOEY
    output wire [ 3:0] dcache_we,         
    output wire [31:0] dcache_addr_o,     
    output wire [31:0] dcache_data_o,     
    input  wire [31:0] dcache_data_i,

    output wire        dcache_req_valid_o,
    input  wire        dcache_rsp_valid_i,

    output wire        outR,
    input  wire        inR,
    output reg  [50:0] data_to,
    input  wire [50:0] data_from,
    output wire        inA,
    input  wire        outA
    
    );
    
    //CPU <-> MEMOEY 传送时 与 MESH无关 
    //CPU <-> MESH   传送时 与 MEMORY 无关
    
    //MESH 数据包格式 1bit wen + 8bit addr + 32bit data + 10xy 
    
    //cpu   -> local
    //uart  -> west
    //gpio  -> south
    //timer -> north

    /******************** 来自CPU的信号解析 ********************/
    reg  [31:0] r_data_bus_data_o;
    // 信号拆分
    wire        w_meshWen_1;     // mesh数据包写使能位
    wire [ 7:0] w_meshAddr_8;    // mesh数据包地址段
    wire [31:0] w_meshData_32;   // mesh数据包数据段
    wire [ 4:0] w_meshX_5;       // mesh数据包X方向段
    wire [ 4:0] w_meshY_5;       // mesh数据包Y方向段
                               
    // 信号重命名            
    wire w_toMesh_1;             // 与Mesh交互
    wire w_toCache_1;            // 与cache交互
    wire w_toUART_1;             // 与UART交互
    wire w_toGPIO_1;             // 与GPIO交互
    wire w_toTIMER_1;            // 与TIMER交互
    wire w_toSPI_1;              // 与SPI交互
    
    assign w_toMesh_1    = data_req_valid_i & |data_bus_addr_i[19:16];  
    assign w_toCache_1   = data_req_valid_i & ~|data_bus_addr_i[19:16]; 
    assign w_toUART_1    = data_req_valid_i & data_bus_addr_i[16];      
    assign w_toGPIO_1    = data_req_valid_i & data_bus_addr_i[17];      
    assign w_toTIMER_1   = data_req_valid_i & data_bus_addr_i[18];      
    assign w_toSPI_1     = data_req_valid_i & data_bus_addr_i[19];    
    
    // 写使能信号输出
    assign dcache_we     =  w_toCache_1?data_bus_we :4'b0;                        // dcache写使能
    assign w_meshWen_1   = |data_bus_we & w_toMesh_1;                             // mesh数据包中写使能位
    wire w_wemem_1 = |dcache_we;                                                 
    // 地址信号输出                                                               // 当与cache交互时,输出至dcache的地址为CPU输入的访问地址
    assign dcache_addr_o = data_bus_addr_i         & {32{w_toCache_1}};           // 当与mesh交互时,输出至mesh网中数据包内地址段为CPU输入的访问地址低八位
    assign w_meshAddr_8  = data_bus_addr_i[7:0]    & { 8{w_toMesh_1 }};          
    // 数据信号输出                                                               // 当与cache交互时,输出至dcache的数据为CPU输入的数据
    assign dcache_data_o = data_bus_data_i & {32{w_toCache_1}};                   // 当与mesh交互时,输出至mesh网中数据包内数据段的数据为CPU输入的数据
    assign w_meshData_32 = data_bus_data_i & {32{w_toMesh_1 }};                  
    // mesh传输方向解析(生成mesh数据包方向部分)
    assign w_meshX_5     = {{5{w_toUART_1}}                & {5'b00001}}       
                         | {{5{w_toGPIO_1|w_toTIMER_1}}    & {5'b00000}}       
                         | {{5{w_toSPI_1   }}              & {5'b10001}};
`ifdef BUS_BY_FUTONG                    
    assign w_meshY_5     = {{5{w_toUART_1|w_toSPI_1  }}    & {5'b00000}}      
                         | {{5{w_toGPIO_1    }}            & {5'b00001}}      
                         | {{5{w_toTIMER_1   }}            & {5'b10001}};     
 `endif

`ifdef BUS_BY_WEIJIE
    assign w_meshY_5     = {{5{w_toUART_1|w_toSPI_1  }}    & {5'b00000}}      
                         | {{5{w_toGPIO_1    }}            & {5'b10001}}      
                         | {{5{w_toTIMER_1   }}            & {5'b00001}};     

`endif                        
    wire r_data_rsp_valid_o;
	
    // CPU与cache握手信号输出
    assign dcache_req_valid_o = data_req_valid_i & w_toCache_1;     
    assign data_bus_data_o    = w_toCache_1 ? dcache_data_i : r_data_bus_data_o;
	
    assign data_rsp_valid_o     = {{w_toCache_1 &  w_wemem_1 }  & 1'b1                  }   //写Cache直接应答
                                | {{w_toCache_1 & !w_wemem_1 }  & dcache_rsp_valid_i    }   //读Cache等待应答后传递
                                | {w_toMesh_1   & r_data_rsp_valid_o                    };  //Mash应答来自寄存器

`ifdef DC_ENV
    reg sendtrig;
    reg [50:0] data_pre;
    wire req,fireout,fireIn,fireIn2,outR0,outA0,outR1,outA1,outR2,outA2,negoutR,negfire;
    always @(posedge clk or negedge rstn) begin
        if(!rstn) begin
          sendtrig <= 0;
          data_pre <= 51'b0;
        end else begin
          sendtrig <= w_toMesh_1;
          data_pre <= {w_meshWen_1,w_meshAddr_8,w_meshData_32,w_meshX_5,w_meshY_5};
        end 
    end
    always @(posedge fireout or negedge rstn) begin
        if(!rstn) begin
            data_to <= 51'b0;
        end else begin
            data_to <= data_pre;
        end
    end
    always @(posedge fireIn or negedge rstn) begin
        if(!rstn) begin
             r_data_bus_data_o <= 32'b0;
        end else begin
             r_data_bus_data_o <= data_from[41:10];
        end
    end
    posClick click0(.inR(inR), .inA(inA), .outR(outR0), .outA(outA0), .fire(fireIn), .rst(rstn));
    bidirDelay1U delay0(.inR(outR0), .inA(outA0), .outR(outR1), .outA(outA1));
    posClick click1(.inR(outR1), .inA(outA1), .outR(outR2), .outA(outA2), .fire(fireIn2), .rst(rstn));
    natSink receiver0(.inR(outR2), .inA(outA2));

    contTap sender(.trig(sendtrig), .req(req), .rst(rstn));
    posClick click2(.inR(req),  .outR(outR), .outA(outA), .fire(fireout), .rst(rstn));
    negClick negclick( .inR(req ^~ outA), .outR(negoutR), .outA(negoutR), .fire(negfire), .rst(rstn) );

    fire2SyncPluse f2p_rsp(.fire(fireIn2 | (data_pre[50] & negfire & (req ^~ outA))),.clk(clk),.rstn(rstn),.rise(r_data_rsp_valid_o));
`else
                           
    reg  state; reg r_wait_1,r_waitt_1;
    localparam      IDLE = 1'b0;
    localparam      WAIT = 1'b1;
    reg r_inR;
    reg r_outR;

    `ifdef BUS_BY_FUTONG         //ASIC DELY
        wire delay; 
        delay2U delay1(.inR(r_outR),.outR(delay));
        delay2U delay2(.inR(delay),.outR(outR));
    `else // USE LUT DELAY
        `ifndef POST_SYNTHSIS_SIMULATION
            assign #3 outR = r_outR ;
        `else 
            wire delay;   
            (* dont_touch = "true" *)
            LUT1 #(.INIT(2'b10)) delay1(
                   .O(delay),   
                   .I0(r_outR)      
                );
            (* dont_touch = "true" *)    
            LUT1 #(.INIT(2'b10)) delay2(
                  .O(outR),   
                  .I0(delay)      
               );
        `endif   
    `endif

    wire [50:0] w_data_to = {w_meshWen_1,w_meshAddr_8,w_meshData_32,w_meshX_5,w_meshY_5};
                            
    assign inA = inR;

    wire fire1 = !r_data_rsp_valid_o & !r_wait_1 & !r_waitt_1 & w_toMesh_1;
    wire fire2 = inR != r_inR;

    always @(posedge clk or negedge rstn) begin
        if(!rstn) begin
            r_outR          <= 0;
            r_inR       <= 0;
            state              <= 0;
            r_data_rsp_valid_o <= 0;
            r_data_bus_data_o  <= 0;
            r_wait_1           <= 0;
            data_to            <= 0;
            r_waitt_1 <= 0;
        end
        else begin
            r_inR       <= inR;
            r_data_rsp_valid_o <= 0;
            r_waitt_1 <= r_wait_1;
            //r_wait_1 <= r_data_rsp_valid_o;
            case(state)
                IDLE: begin r_wait_1 <= 0;
                            if(fire1) begin
                                r_outR <= ~r_outR;
                                data_to <= w_data_to;
                                if(w_meshWen_1) begin
                                    state <= IDLE; 
                                    r_data_rsp_valid_o <= 1'b1;
                                end  else begin
                                    state <= WAIT;//读等待返回
                                end
                            end
                            else begin
                                state <= IDLE;
                                
                            end
                        end 
                WAIT: begin r_wait_1 <= 1;
                            if(fire2)//out_R没有翻转
                            begin
                                state              <= IDLE;
                                r_data_bus_data_o  <= data_from[42:10];    
                                r_data_rsp_valid_o <= 1'b1;        
                            end else begin
                                state <= WAIT;
                            end  
                        end
            endcase
            end
        end

`endif

endmodule    
